/**
 * cstring.h
 */
#pragma once
#include <sys/cdefs.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

#ifndef CSTRING_MACROS
#define CSTRING_MACROS
#define CSTRING_ALIGN8  __attribute__ ((aligned(8)))
#define CSTRING_ALIGN16 __attribute__ ((aligned(16)))
#define CSTRING_ALIGN32 __attribute__ ((aligned(32)))
#define CSTRING_PERMANENT 1
#define CSTRING_INTERNING 2
#define CSTRING_ONSTACK 4
#define CSTRING_INTERNING_SIZE 32
#define CSTRING_STACK_SIZE 128
#endif

struct cstring_data
{
    char* cstr;
    uint32_t hash_size;
    uint16_t type;
    uint16_t ref;
} CSTRING_ALIGN8;

typedef struct _cstring_buffer
{
    struct cstring_data* data;
} CSTRING_ALIGN8 cstring_buffer[1];

typedef struct cstring_data* cstring;

#define cstring_make_buffer(var) \
	char var##_cstring [CSTRING_STACK_SIZE] = {'\0'};	\
	struct cstring_data var##_cstring_data = {var##_cstring , 0, CSTRING_ONSTACK, 0};	\
	cstring_buffer var;	\
	var->data = &var##_cstring_data;

#ifdef __cplusplus
#define cstring_make_literal(var, cstr)	\
	static cstring var = NULL;	\
	if (var) {} else {	\
		cstring tmp = cstring_persist(cstr, (sizeof(cstr)/sizeof(char))-1);	\
		if (!__sync_bool_compare_and_swap((size_t*)(&var), NULL, (size_t)tmp)) {	\
			cstring_free_persist(tmp);	\
		}	\
	}
#else
#define cstring_make_literal(var, cstr) \
    static cstring var = NULL;  \
    if (var) {} else {  \
        cstring tmp = cstring_persist(""cstr, (sizeof(cstr)/sizeof(char))-1);   \
        if (!__sync_bool_compare_and_swap((size_t*)(&var), NULL, (size_t)tmp)) {    \
            cstring_free_persist(tmp);  \
        }   \
    }
#endif

#define cstring_close(var) \
	if ((var)->data->type != 0) {} \
    else { cstring_release((var)->data); }


#ifdef __cplusplus
extern "C" {
#endif

/* low level api, don't use directly */
cstring cstring_persist(const char* cstr, size_t sz);

void cstring_free_persist(cstring s);

/* public api */
cstring cstring_grab(cstring s);

cstring cstring_cat(cstring_buffer sb, const char* str);

cstring cstring_vprintf(cstring_buffer sb, const char* format, ...) __attribute__((format(printf, 2, 3)));

int cstring_equal(cstring a, cstring b);

uint32_t cstring_hash(cstring s);

void cstring_release(cstring s);

#ifdef __cplusplus
}
#endif

